/*
 * @Author: Blake He
 * @Date: 2022-09-05 10:35:50
 * @Description: 七牛vite上传插件
 * @LastEditTime: 2023-04-03 16:24:26
 * @LastEditors: yuyang
 */

import glob from 'glob'
import chalk from 'chalk'
import path from 'path'
import { URL } from 'url'
import anymatch from 'anymatch'
import fs from 'fs'
import { normalizePath } from 'vite'
import { v4 as uuid } from 'uuid'
import Qiniu from './qiniu'
import Reporter from './reporter'
import utils from './utils'

const matchers = ['**.js', '**.css', '**.ico', '**/img/**', '**/fonts/**']

const removeDir = (dir) => {
    if (fs.existsSync(dir)) {
        const files = fs.readdirSync(dir)
        for (let i = 0; i < files.length; i++) {
            const newPath = path.join(dir, files[i])
            const stat = fs.statSync(newPath)
            if (stat.isDirectory()) {
                removeDir(newPath)
            } else {
                fs.unlinkSync(newPath)
            }
        }
        if (fs.existsSync(dir)) {
            fs.rmdirSync(dir)
        }
    }
}

function vitePluginQiniuOss(openUpload, mode) {
    try {
        console.log('vitePluginQiniuOss开始执行')
        let baseConfig = '/'
        let buildConfig: any = ''
        const options = utils.getFileOptions()
        const reporter = new Reporter('\n')

        if (!openUpload) {
            reporter.stop()
            return
        }

        if (!utils.validateOptions(options)) {
            reporter.stop()
            return
        }

        return {
            name: 'vite-plugin-qiniu-oss',
            enforce: 'post', // 在 Vite 构建插件之后调用该插件
            apply: 'build', // 只在 build 模式启用
            configResolved: async (config) => {
                baseConfig = config.base
                buildConfig = config.build
            },
            // 打包完成后执行上传
            closeBundle: async () => {
                const outDirPath = normalizePath(path.resolve(normalizePath(buildConfig.outDir)))

                const createOssOption: any = { ...options }
                const { accessKey, secretKey, sit, prod } = createOssOption
                const qiniu = new Qiniu({
                    accessKey,
                    secretKey,
                    bucket: mode === 'sit' ? sit.bucket : prod.bucket,
                    domain: mode === 'sit' ? sit.domain : prod.domain
                })

                const files = await glob.sync(`${outDirPath}/**/*`, {
                    strict: true,
                    nodir: true,
                    dot: true,
                    ignore: '**/*.html'
                })

                // const filenames = Object.keys('/assets').filter(
                //     (c) => c.includes('hash=') && anymatch(this.matchers, c)
                // )

                reporter.log = '=====qiniu oss 开始上传=====  \n'

                const startTime = new Date().getTime()
                const releaseFiles = files.map((item) => {
                    return item.split(outDirPath)[1]
                })

                reporter.log = '=====正在获取历史数据=====  \n'

                // 获取文件日志
                const {
                    uploadTime,
                    prev: prevFiles = [],
                    current: currentFiles = []
                } = await utils.getLogFile(createOssOption, qiniu)

                // 合并去重，提取最终要上传和删除的文件
                const { uploadFiles, deleteFiles } = utils.combineFiles(prevFiles, currentFiles, releaseFiles)

                reporter.log = `=====将上传 ${uploadFiles.length} 个文件=====`

                const uploadFileTasks = uploadFiles.map((filename, index) => {
                    const localUrl = outDirPath + filename
                    const uploadPath = createOssOption.uploadPath.replace(/\//g, '')
                    const key = uploadPath + filename
                    const id = uuid()
                    const callback = (taskId: string, process: number) => { }
                    return async () => {
                        await qiniu.putFile(id, key, localUrl, {}, callback)
                    }
                })

                try {
                    await utils.mapLimit(uploadFileTasks, createOssOption.batch, (task, next) => {
                        const fn = async () => {
                            try {
                                const res = await task()
                                next(null, res)
                            } catch (err) {
                                next(err)
                            }
                        }

                        fn()
                    })
                } catch (e) {
                    console.error(chalk.bold.red('\n\n上传失败:'))
                    // callback(e)
                }

                const duration = (new Date().getTime() - startTime) / 1000
                console.log(`=====上传完毕, cost ${duration.toFixed(2)}s`)

                reporter.text = '=====正在写入日志...\n'
                await utils.writeLogFile({ currentFiles, releaseFiles, qiniu, createOssOption })
                reporter.log = '=====日志记录完毕\n'

                reporter.succeed('===== \n')
                console.log(chalk.bold.green('==== 七牛CDN上传完毕 ==== \n'))

                // 移除打包文件下静态资源
                const assetsDirPath = path.resolve(__dirname, `${outDirPath}/assets`)
                const iconsDirPath = path.resolve(__dirname, `${outDirPath}/icons`)
                removeDir(assetsDirPath)
                removeDir(iconsDirPath)

                console.log(chalk.bold.green('==== 移除打包目录下静态资源assets、icons文件夹 ==== \n'))
            }
        }
    } catch (error) {
        console.error(error)
        console.error(chalk.bold.red('\n\n上传失败:'))
        throw error
    }
}

export default vitePluginQiniuOss
